package MainControl;

import Instrument.TestingMachine;
import Model.Pulsator;
import Model.Refrigerator;
import Tool.GlobalVariable;
import Tool.HexString;
import Tool.WriteLog;
import Tool.XMLReader;
import Model.Roller;

import java.io.*;
import java.net.*;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public class MainControl implements Runnable {
    public HashMap<Integer, TestingMachine> machines = new HashMap<>();
    public HashMap<Integer, OutputStream> commandWriters = new HashMap<>();
    public HashMap<Integer, InputStream> dataReaders = new HashMap<>();
    public HashMap<Integer, Socket> connections = new HashMap<>();
    private Socket dataBackSocket;
    private OutputStream databackStream;
    private OutputStream databackStreamHex;
    private PrintWriter databackWriter;
    private volatile static MainControl mainControl;
    private ServerSocket serverSocketHex;
    private Socket socketHex;

    SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    String remark = "";//定义波轮还是滚筒，添加控制台信息使用

    //设置重新初试话Socket,其中machineNo为configure中的TotalTestUnitID的value
    public synchronized void reInit(Integer machineNo) {
        XMLReader configureReader = XMLReader.getInstance();
        TestingMachine tempMachine = new TestingMachine();
        tempMachine.setIP(configureReader.getIPbyID(String.valueOf(machineNo)));
        tempMachine.setPort(configureReader.getPortbyID(String.valueOf(machineNo)));
        tempMachine.setTotalTestUnitID(String.valueOf(machineNo));
        tempMachine.setTestingStatus(false);
        machines.remove(tempMachine);
        machines.put(machineNo, tempMachine);
        Socket tempSocket = null;
        OutputStream tempWriter  = null;
        InputStream tempReader  = null;
        try {
            if(tempMachine == null){
                return;
            }
            String ip = tempMachine.getIP();
            String s = tempMachine.getPort();
            System.out.println("port: " + s);
            int port = Integer.parseInt(s);
            tempSocket = new Socket();
            tempSocket.connect(new InetSocketAddress(ip, port), 1000);
            tempSocket.setSoTimeout(1000);
            tempSocket.setKeepAlive(true);
        } catch (Exception e) {
            e.printStackTrace();
            WriteLog.write(e.toString(),machineNo);
        }
        connections.remove(machineNo);
        connections.put(machineNo, tempSocket);
        try {
            tempWriter = tempSocket.getOutputStream();
            if(tempWriter == null){
                return;
            }
        } catch (Exception e) {
            e.printStackTrace();
            WriteLog.write(e.toString(),machineNo);
        }
        commandWriters.remove(machineNo);
        commandWriters.put(machineNo, tempWriter);

        try {
            tempReader = tempSocket.getInputStream();
            if (tempReader==null){
                return;
            }
        } catch (Exception e) {
            e.printStackTrace();
            WriteLog.write(e.toString(),machineNo);
        }
        dataReaders.remove(machineNo);
        dataReaders.put(machineNo, tempReader);
        System.out.println(format.format(new Date()) + "--------------台位" + machineNo + "初始化结束---------------");
        WriteLog.write(format.format(new Date()) + "--------------台位" + machineNo + "初始化结束---------------",machineNo);
    }

    //创建单例
    public static MainControl getMainControl() {
        if (mainControl == null) {
            synchronized (MainControl.class) {
                if (mainControl == null) {
                    mainControl = new MainControl();
                }

            }
        }
        return mainControl;
    }

    //关闭socket
    public synchronized void closeSocket(Integer machineNum) {
        try {
            dataReaders.get(machineNum).close();
            dataReaders.remove(machineNum);
            commandWriters.get(machineNum).close();
            commandWriters.remove(machineNum);
            connections.get(machineNum).close();
            connections.remove(machineNum);
        } catch (IOException e) {
            e.printStackTrace();
            WriteLog.write("closeSocket方法有错误",machineNum);
            WriteLog.write(e.toString(),machineNum);
        }

    }
    //接收消息

    public synchronized void getMsg() {
        String collectedValue = "";
        String result6D = "";
        String result7D = "";
        String date7DTemp = "";
        String alarm = "";
        int readCount = 0;
        byte[] readBuffer = new byte[4096];
        try {
            databackStream = dataBackSocket.getOutputStream();
            databackStreamHex = socketHex.getOutputStream();
            if (databackWriter == null)
                databackWriter = new PrintWriter(databackStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println("-----------------接收数据消息中-----------------");
        //发送消息
        for (Map.Entry<String, String> entity1 : GlobalVariable.testingUnitsID.entrySet()) {
            Integer currentTestUnitID1 = Integer.parseInt(entity1.getKey());//当前正在测试的台位号
            TestingMachine tempMachine = machines.get(currentTestUnitID1);
            if (connections.get(currentTestUnitID1) == null) {
                try {
                    Socket tempConnection = new Socket();
                    if (tempMachine == null) {
                        continue;
                    }
                    InetSocketAddress addr = new InetSocketAddress(tempMachine.getIP(), Integer.parseInt(tempMachine.getPort()));
                    tempConnection.connect(addr,1000);
                    tempConnection.setSoTimeout(1000);
                    tempConnection.setKeepAlive(true);
                    connections.remove(currentTestUnitID1);
                    connections.put(currentTestUnitID1, tempConnection);
                } catch (IOException e) {
                    e.printStackTrace();
                    System.out.println(format.format(new Date()) + "第" + currentTestUnitID1 + "个设备无法建立socket连接！");
                    WriteLog.write(format.format(new Date()) + "第" + currentTestUnitID1 + "个设备无法建立socket连接！",currentTestUnitID1);
                    reInit(currentTestUnitID1);
                    continue;
                }
            }
            if (commandWriters.get(currentTestUnitID1) == null) {
                try {
                    OutputStream tempWriter = connections.get(currentTestUnitID1).getOutputStream();
                    commandWriters.remove(currentTestUnitID1);
                    commandWriters.put(currentTestUnitID1, tempWriter);
                } catch (SocketException e) {
                    e.printStackTrace();
                    WriteLog.write(e.toString(),currentTestUnitID1);
                    WriteLog.write("台位"+currentTestUnitID1+"重新进行初始化",currentTestUnitID1);
                    reInit(currentTestUnitID1);
                } catch (IOException e) {
                    e.printStackTrace();
                    System.out.println(format.format(new Date()) + "第" + currentTestUnitID1 + "个设备无法打开输出流！");
                    WriteLog.write(format.format(new Date()) + "第" + currentTestUnitID1 + "个设备无法打开输出流！",currentTestUnitID1);
                    continue;
                }
            }
            if (dataReaders.get(currentTestUnitID1) == null) {
                try {
                    InputStream tempReader = connections.get(currentTestUnitID1).getInputStream();
                    dataReaders.remove(currentTestUnitID1);
                    dataReaders.put(currentTestUnitID1, tempReader);
                } catch (IOException e) {
                    e.printStackTrace();
                    System.out.println(format.format(new Date()) + "第" + currentTestUnitID1 + "个设备无法打开输入流！");
                    WriteLog.write(format.format(new Date()) + "第" + currentTestUnitID1 + "个设备无法打开输出流！",currentTestUnitID1);
                    continue;
                }
            }

            try {
            	 
                byte getData2[] = new byte[13];
                getData2[0] = (byte) 0xFF;
                getData2[1] = (byte) 0xFF;
                getData2[2] = (byte) 0x0A;
                getData2[3] = (byte) 0x00;
                getData2[4] = (byte) 0x00;
                getData2[5] = (byte) 0x00;
                getData2[6] = (byte) 0x00;
                getData2[7] = (byte) 0x00;
                getData2[8] = (byte) 0x00;
                getData2[9] = (byte) 0x01;
                getData2[10] = (byte) 0x4D;
                getData2[11] = (byte) 0x01;
                getData2[12] = (byte) 0x59;
                System.out.println("-------" + commandWriters.get(currentTestUnitID1));
                commandWriters.get(currentTestUnitID1).write(getData2);
                commandWriters.get(currentTestUnitID1).flush();

            } catch (SocketTimeoutException e) {
                System.out.println("--------------------台位:"+currentTestUnitID1+"的SocketTimeoutException------------------");
                WriteLog.write("--------------------台位:"+currentTestUnitID1+"的SocketTimeoutException------------------",currentTestUnitID1);
                e.printStackTrace();
                //捕获到超时信息，马上继续执行
                continue;
            } catch (SocketException e) {
                e.printStackTrace();
                //捕获到连接异常，重新进行初始化
                WriteLog.write(e.toString(),currentTestUnitID1);
                System.out.println("--------------------台位"+currentTestUnitID1+"的SocketException------------------");
                WriteLog.write("--------------------台位"+currentTestUnitID1+"的SocketException------------------",currentTestUnitID1);
                reInit(currentTestUnitID1);
            } catch (IOException e) {
                e.printStackTrace();
                WriteLog.write(e.toString(),currentTestUnitID1);
                System.out.println(format.format(new Date()) + "第" + currentTestUnitID1 + "个设备采集异常！");
                WriteLog.write(format.format(new Date()) + "第" + currentTestUnitID1 + "个设备采集异常！",currentTestUnitID1);
                System.out.println("--------------------尝试新建Socket连接----------------");
                WriteLog.write("--------------------尝试新建Socket连接----------------",currentTestUnitID1);

                //一旦发生采集异常本台位的采集信息会停止，需要重新开测
                try {
                    connections.get(currentTestUnitID1).close();
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
                reInit(currentTestUnitID1);
                //continue;
            }
        }
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //接收消息
        for (Map.Entry<String, String> entity : GlobalVariable.testingUnitsID.entrySet()) {
            System.out.println("GlobalVariable.testingUnitsID.size():"+ GlobalVariable.testingUnitsID.size());
            Integer currentTestUnitID = Integer.parseInt(entity.getKey());//当前正在测试的台位号
            String currentModelAndType = entity.getValue();//当前测试的台位所对应的洗衣机类型
            try {
                InputStream input = dataReaders.get(currentTestUnitID);
                if (input == null){
                    continue;
                }
                readCount = input.available();
                System.out.println("readCount:" + readCount);
                if (readCount > 0) {
                    readCount = dataReaders.get(currentTestUnitID).read(readBuffer);
                }
            } catch (SocketTimeoutException e) {
                e.printStackTrace();
                WriteLog.write(e.toString(),currentTestUnitID);
                System.out.println("--------------------SocketTimeoutException------------------");
                WriteLog.write("--------------------SocketTimeoutException------------------",currentTestUnitID);
                //捕获到超时信息，马上继续执行
                continue;
            } catch (SocketException e) {
                e.printStackTrace();
                WriteLog.write(e.toString(),currentTestUnitID);
                System.out.println("--------------------SocketException------------------");
                WriteLog.write("--------------------SocketException------------------",currentTestUnitID);
                //捕获到连接异常，重新进行初始化
                reInit(currentTestUnitID);
            } catch (IOException e) {
                e.printStackTrace();
                WriteLog.write(e.toString(),currentTestUnitID);
                WriteLog.write(format.format(new Date()) + "第" + currentTestUnitID + "个设备采集异常！",currentTestUnitID);
                System.out.println("--------------------尝试新建Socket连接----------------");
                WriteLog.write("--------------------尝试新建Socket连接----------------",currentTestUnitID);
                //一旦发生采集异常本台位的采集信息会停止，需要重新开测
                try {
                    connections.get(currentTestUnitID).close();
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
                reInit(currentTestUnitID);
            }catch(Exception e){
                e.printStackTrace();
            }
            collectedValue = HexString.parseString(readBuffer, readCount).trim();
            collectedValue = collectedValue.replaceAll(" +", " ");
            //去掉FF 55的情况
            System.out.println(format.format(new Date()) + "台位:" + currentTestUnitID + ">>>>>>>>>>>>收集到数据:>>>>>>>>>>>>>>>" + collectedValue);
            WriteLog.write(format.format(new Date()) + "台位:" + currentTestUnitID + ">>>>>>>>>>>>收集到数据:>>>>>>>>>>>>>>>" + collectedValue,currentTestUnitID);
            String responses[] = collectedValue.split("FF FF");
            //去掉空格,同时将FF 55替换成FF
            for (int j = 1; j < responses.length; j++) {
                responses[j] = responses[j].trim();
                responses[j] = responses[j].replaceAll("FF 55", "FF");
            }
            for (int responseCount = 1; responseCount < responses.length; responseCount++) {
                System.out.println(format.format(new Date()) + "台位" + currentTestUnitID + ">>>>>>>>>>>输出第" + responseCount + "条采集数据:>>>>>>>>>>>>>>" + responses[responseCount]);
                WriteLog.write(format.format(new Date()) + "台位" + currentTestUnitID + ">>>>>>>>>>>输出第" + responseCount + "条采集数据:>>>>>>>>>>>>>>" + responses[responseCount],currentTestUnitID);
                //判断是否是C1 D12G3LU1型号 发命令FF FF 0C 00 00 00 00 00 00 F1 00 00 00 50 4D
                //滚筒
                //wifi确认信号
                byte command[] = new byte[15];
                command[0] = (byte) 0xFF;
                command[1] = (byte) 0xFF;
                command[2] = (byte) 0x0C;
                command[3] = (byte) 0x00;
                command[4] = (byte) 0x00;
                command[5] = (byte) 0x00;
                command[6] = (byte) 0x00;
                command[7] = (byte) 0x00;
                command[8] = (byte) 0x00;
                command[9] = (byte) 0xF1;
                command[10] = (byte) 0x00;
                command[11] = (byte) 0x00;
                command[12] = (byte) 0x00;
                command[13] = (byte) 0x50;
                command[14] = (byte) 0x4D;

                //接收到命令停止发送命令的指令
                byte getData[] = new byte[11];
                getData[0] = (byte) 0xFF;
                getData[1] = (byte) 0xFF;
                getData[2] = (byte) 0x08;
                getData[3] = (byte) 0x00;
                getData[4] = (byte) 0x00;
                getData[5] = (byte) 0x00;
                getData[6] = (byte) 0x00;
                getData[7] = (byte) 0x00;
                getData[8] = (byte) 0x00;
                getData[9] = (byte) 0x09;
                getData[10] = (byte) 0x11;
                try {
                    commandWriters.get(currentTestUnitID).write(command);
                    if (responses[responseCount].trim().length() > 40) {
                        String ifSendKey = responses[responseCount].substring(21, 23);
                        if (ifSendKey.equals("63")){
                        	byte setKey[] = new byte[14];
                            setKey[0] = (byte) 0xFF;
                            setKey[1] = (byte) 0xFF;
                            setKey[2] = (byte) 0x0B;
                            setKey[3] = (byte) 0x00;
                            setKey[4] = (byte) 0x00;
                            setKey[5] = (byte) 0x00;
                            setKey[6] = (byte) 0x00;
                            setKey[7] = (byte) 0x00;
                            setKey[8] = (byte) 0x00;
                            setKey[9] = (byte) 0X64;
                            setKey[10] = (byte) 0x00;
                            setKey[11] = (byte) 0x00;
                            setKey[12] = (byte) 0x00;
                            setKey[13] = (byte) 0x6F;
                            commandWriters.get(currentTestUnitID).write(setKey);
                            commandWriters.get(currentTestUnitID).flush();
                        }
                        	
                        String responseType = responses[responseCount].substring(24, 29);
                        //冰箱
                        if (currentModelAndType.equals("1")) {
                            if (responseType.equals("7D 01")) {
                            	date7DTemp = responses[responseCount].trim();
                                String pulsator7D[] = responses[responseCount].trim().split(" ");
                                if (pulsator7D.length >= 85) {
                                    result7D = Refrigerator.get7DData("FF FF " + responses[responseCount].trim());
                                    result7D = "!DATA#" + "UNITID:" + currentTestUnitID + "#" + result7D;
                                } else {
                                    System.out.println("------------接收的波轮洗衣机数据不完整----------------");
                                }
                            }
                            if (responseType.equals("0F 5A")) {
                                String pulsatorAlarm[] = responses[responseCount].trim().split(" ");
                                if (pulsatorAlarm.length == 19) {
                                    alarm = new Refrigerator().getAlarm("FF FF " + responses[responseCount].trim());
                                    alarm = "!ALARM#" + "UNITID:" + currentTestUnitID + "#" + alarm;
                                    commandWriters.get(currentTestUnitID).write(getData);
                                    commandWriters.get(currentTestUnitID).flush();
                                    if (!alarm.contains("报警解除")) {
                                        databackStream.write(alarm.getBytes());
                                        databackStream.flush();
                                        System.out.println("返回报警信息:" + alarm);
                                        WriteLog.write("返回报警信息:" + alarm,currentTestUnitID);
                                    }
                                }
                            }
                        }
                    } else {
                        System.out.println("---------------接收到命令缺少7D跟alarm的标识位信息-------------------");
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            if (!result7D.equals("")) {
                try {
                    System.out.println(format.format(new Date()) + ">>>>>>>>>>>>>>>>>>>>>>>" + remark + "返回7D信息:" + result7D);
                    WriteLog.write(format.format(new Date()) + ">>>>>>>>>>>>>>>>>>>>>>>" + remark + "返回7D信息:" + result7D,currentTestUnitID);
                    String resultHex = "!Hex#" + "UNITID:" + currentTestUnitID + "#" + "FF FF " + date7DTemp;
                    if(date7DTemp!=null&&date7DTemp!=""){
                        databackStreamHex.write(resultHex.getBytes());
                        databackStreamHex.flush();
                        WriteLog.write(format.format(new Date()) + "  " + resultHex, currentTestUnitID);
                    }
                    databackStream.write(result7D.getBytes());
                    databackStream.flush();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (!result7D.equals("")) {
                try {
                    System.out.println(format.format(new Date()) + ">>>>>>>>>>>>>>>>>>>>>>>" + remark + "返回7D信息:" + result7D);
                    WriteLog.write(format.format(new Date()) + ">>>>>>>>>>>>>>>>>>>>>>>" + remark + "返回7D信息:" + result7D,currentTestUnitID);
                    String resultHex = "!Hex#" + "UNITID:" + currentTestUnitID + "#" + "FF FF " + date7DTemp;
                    if(date7DTemp!=null&&date7DTemp!=""){
                        databackStreamHex.write(resultHex.getBytes());
                        databackStreamHex.flush();
                        WriteLog.write(format.format(new Date()) + "  " + resultHex, currentTestUnitID);
                    }
                    databackStream.write(result7D.getBytes());
                    databackStream.flush();
                    result7D = "";
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }

    //使用多线程进行接收数据
    public void run() {
        try {
            ServerSocket
                    dataBackServer = new ServerSocket(7002);

            dataBackSocket = dataBackServer.accept();
            if (dataBackSocket != null) {
                System.out.println("端口7002初始化成功");
            }
            //打开7003端口用来返回原始数据
            serverSocketHex = new ServerSocket(7003);
            socketHex = serverSocketHex.accept();
            if (socketHex != null) {
                System.out.println("端口7003初始化成功");
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        while (true) {
            try {
                byte info[] = new byte[4096];
                InputStream output = dataBackSocket.getInputStream();
                int readCount = output.read(info);
                String s = new String(info, 0, readCount);
                System.out.println(format.format(new Date()) + "接受到的数据：" + s);
                //设置为信息2#checkmsg
                if (s.contains("#")) {
                    System.out.println("进行监测");
                    String taiweiNo[] = s.split("#");
                    Integer noTaiwei = Integer.parseInt(taiweiNo[0]);
                    byte checkData[] = new byte[11];
                    checkData[0] = (byte) 0xFF;
                    checkData[1] = (byte) 0xFF;
                    checkData[2] = (byte) 0x08;
                    checkData[3] = (byte) 0x00;
                    checkData[4] = (byte) 0x00;
                    checkData[5] = (byte) 0x00;
                    checkData[6] = (byte) 0x00;
                    checkData[7] = (byte) 0x00;
                    checkData[8] = (byte) 0x00;
                    checkData[9] = (byte) 0x73;
                    checkData[10] = (byte) 0x7B;
                    commandWriters.get(noTaiwei).write(checkData);
                    //dataReader.get(currentTestingUnitID).read(readBuffer);

                    byte res[] = new byte[4096];
                    InputStream out = connections.get(noTaiwei).getInputStream();
                    int reads = out.read(res);
                    String resu = HexString.parseString(res, reads);
                    System.out.println(format.format(new Date()) + "返回接受的数据是resu：" + resu);
                    //发送信息后马上返回的数据
                    getMsg();
                } else {
                    getMsg();
                }

            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        MainControl m = MainControl.getMainControl();
        System.out.println("-----------准备就绪,请开启主控----------");
        Thread t = new Thread(m);
        CommandControl c = CommandControl.getInstance();
        Thread t1 = new Thread(c);
        t1.start();
        t.start();
    }
}
